#include <graphics/MD2ModelLoader.h>

namespace ne
{
    const int MD2ModelLoader::MD2_MAGIC = 0x32504449;
    const int MD2ModelLoader::MD2_VERSION = 0x8;

    MD2Model* MD2ModelLoader::loadModel(const std::string &fileName) const
    {
        FILE *file = fopen(fileName.c_str(), "rb");
        if (file == 0)
        {
            return 0;
        }
        MD2Header *headerP = new MD2Header();
        fread(headerP, sizeof(MD2Header), 1, file);
        std::cout << "FrameSize = " << headerP->m_iFrameSize << std::endl;
        std::cout << "NumFrames = " << headerP->m_iNumFrames << std::endl;
        std::cout << "NumVertices = " << headerP->m_iNumVertices << std::endl;
        std::cout << "NumTriangles = " << headerP->m_iNumTriangles << std::endl;
        std::cout << "NumSkins = " << headerP->m_iNumSkins << std::endl;
        if (headerP->m_iMagicNum != MD2_MAGIC ||
            headerP->m_iVersion != MD2_VERSION)
        {
            delete headerP;
            return 0;
        }

        MD2Model *modelP = new MD2Model();
        modelP->setFrameNum(headerP->m_iNumFrames);
        modelP->setFrameSize(headerP->m_iNumVertices);

        MD2Skin *skinsP = new MD2Skin[headerP->m_iNumSkins];
	    MD2TexCoord *texCoordsP = new MD2TexCoord[headerP->m_iNumTexCoords];
	    MD2Face *facesP = new MD2Face[headerP->m_iNumTriangles];

        // Next, we start reading in the data by seeking to our skin names offset
	    // Depending on the skin count, we read in each skin for this md2model
	    fseek(file, headerP->m_iOffsetSkins, SEEK_SET);
	    fread(skinsP, sizeof(MD2Skin), headerP->m_iNumSkins, file);
        printf("Texture name: %s\n", skinsP[0]);
        delete[] skinsP;
	
	    // Move the file pointer to the position in the file for texture coordinates
	    // Read in all the texture coordinates in one fell swoop
	    fseek(file, headerP->m_iOffsetTexCoords, SEEK_SET);
	    fread(texCoordsP, sizeof(MD2TexCoord), headerP->m_iNumTexCoords, file);
        MD2Model::TexCoordList *pTextureList = new MD2Model::TexCoordList(headerP->m_iNumTexCoords);
        for (int i=0; i<headerP->m_iNumTexCoords; ++i)
        {
            (*pTextureList)[i].x = float(texCoordsP[i].u)/float(headerP->m_iSkinWidthPx);
            (*pTextureList)[i].y = 1 - float(texCoordsP[i].v)/float(headerP->m_iSkinHeightPx);
        }
        modelP->setTexCoordList(pTextureList);
        delete[] texCoordsP;

        // Move the file pointer to the triangles/face data offset
        // Read in the face data for each triangle (vertex and texCoord indices)
        fseek(file, headerP->m_iOffsetTriangles, SEEK_SET);
	    fread(facesP, sizeof(MD2Face), headerP->m_iNumTriangles, file);
        MD2Model::IndexList *pVertexIndexList = new MD2Model::IndexList(3*headerP->m_iNumTriangles);
        MD2Model::IndexList *pTextureIndexList = new MD2Model::IndexList(3*headerP->m_iNumTriangles);
        for (int i=0; i<headerP->m_iNumTriangles; ++i)
        {
            (*pVertexIndexList)[3*i+0] = facesP[i].m_vVertexIndices[2];
            (*pVertexIndexList)[3*i+1] = facesP[i].m_vVertexIndices[1];
            (*pVertexIndexList)[3*i+2] = facesP[i].m_vVertexIndices[0];

            (*pTextureIndexList)[3*i+0] = facesP[i].m_vTextureIndices[2];
            (*pTextureIndexList)[3*i+1] = facesP[i].m_vTextureIndices[1];
            (*pTextureIndexList)[3*i+2] = facesP[i].m_vTextureIndices[0];
        }
        modelP->setVertexIndexList(pVertexIndexList);
        modelP->setTexCoordIndexList(pTextureIndexList);
        delete[] facesP;

        // Move the file pointer to the vertices (frames)
	    fseek(file, headerP->m_iOffsetFrames, SEEK_SET);
        MD2Model::VertexList *pVertexList = new MD2Model::VertexList(headerP->m_iNumFrames * headerP->m_iNumVertices);
        byte *buffer = new byte[headerP->m_iFrameSize];
        //MD2Model::NormalList *pNormalList = new MD2Model::NormalList(headerP->m_iNumVertices);
	    for (int i=0; i<headerP->m_iNumFrames; ++i)
	    {
		    // Assign our alias frame to our buffer memory
		    MD2AliasFrame *pFrame = (MD2AliasFrame *)buffer;

		    // Read in the first frame of animation
		    fread(pFrame, 1, headerP->m_iFrameSize, file);

		    // Copy the name of the animation to our frames array
		    // strcpy(framesP[i].m_vFrameName, pFrame->m_vName);
            printf("Frame name: %s\n", pFrame->m_vName);

		    for (int j=0; j<headerP->m_iNumVertices; ++j)
		    {
                int p = headerP->m_iNumVertices * i + j;
                (*pVertexList)[p].x = pFrame->m_vAliasVertices[j].m_vVertex[0] * pFrame->m_vScale[0] + pFrame->m_vTranslate[0];
                (*pVertexList)[p].y = pFrame->m_vAliasVertices[j].m_vVertex[2] * pFrame->m_vScale[2] + pFrame->m_vTranslate[2];
                (*pVertexList)[p].z = -1 * (pFrame->m_vAliasVertices[j].m_vVertex[1] * pFrame->m_vScale[1] + pFrame->m_vTranslate[1]);
		    }
	    }
        modelP->setVertexList(pVertexList);
        delete[] buffer;

        fclose(file);
        delete headerP;

        return modelP;
    }
}

